home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / lib / tk2.3 / dist / tkPreserve.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-15  |  6.2 KB  |  237 lines

  1. /* 
  2.  * tkPreserve.c --
  3.  *
  4.  *    This file contains a collection of procedures that are used
  5.  *    to make sure that widget records and other data structures
  6.  *    aren't reallocated when there are nested procedures that
  7.  *    depend on their existence.
  8.  *
  9.  * Copyright 1991 Regents of the University of California
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that this copyright
  13.  * notice appears in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /user6/ouster/wish/RCS/tkPreserve.c,v 1.6 92/06/15 13:44:51 ouster Exp $ SPRITE (Berkeley)";
  21. #endif /* not lint */
  22.  
  23. #include "tkConfig.h"
  24. #include "tk.h"
  25.  
  26. /*
  27.  * The following data structure is used to keep track of all the
  28.  * Tk_Preserve calls that are still in effect.  It grows as needed
  29.  * to accommodate any number of calls in effect.
  30.  */
  31.  
  32. typedef struct {
  33.     ClientData clientData;    /* Address of preserved block. */
  34.     int refCount;        /* Number of Tk_Preserve calls in effect
  35.                  * for block. */
  36.     int mustFree;        /* Non-zero means Tk_EventuallyFree was
  37.                  * called while a Tk_Preserve call was in
  38.                  * effect, so the structure must be freed
  39.                  * when refCount becomes zero. */
  40.     Tk_FreeProc *freeProc;    /* Procedure to call to free. */
  41. } Reference;
  42.  
  43. static Reference *refArray;    /* First in array of references. */
  44. static int spaceAvl = 0;    /* Total number of structures available
  45.                  * at *firstRefPtr. */
  46. static int inUse = 0;        /* Count of structures currently in use
  47.                  * in refArray. */
  48. #define INITIAL_SIZE 2
  49.  
  50. /*
  51.  *----------------------------------------------------------------------
  52.  *
  53.  * Tk_Preserve --
  54.  *
  55.  *    This procedure is used by a procedure to declare its interest
  56.  *    in a particular block of memory, so that the block will not be
  57.  *    reallocated until a matching call to Tk_Release has been made.
  58.  *
  59.  * Results:
  60.  *    None.
  61.  *
  62.  * Side effects:
  63.  *    Information is retained so that the block of memory will
  64.  *    not be freed until at least the matching call to Tk_Release.
  65.  *
  66.  *----------------------------------------------------------------------
  67.  */
  68.  
  69. void
  70. Tk_Preserve(clientData)
  71.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  72. {
  73.     register Reference *refPtr;
  74.     int i;
  75.  
  76.     /*
  77.      * See if there is already a reference for this pointer.  If so,
  78.      * just increment its reference count.
  79.      */
  80.  
  81.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  82.     if (refPtr->clientData == clientData) {
  83.         refPtr->refCount++;
  84.         return;
  85.     }
  86.     }
  87.  
  88.     /*
  89.      * Make a reference array if it doesn't already exist, or make it
  90.      * bigger if it is full.
  91.      */
  92.  
  93.     if (inUse == spaceAvl) {
  94.     if (spaceAvl == 0) {
  95.         refArray = (Reference *) ckalloc((unsigned)
  96.             (INITIAL_SIZE*sizeof(Reference)));
  97.         spaceAvl = INITIAL_SIZE;
  98.     } else {
  99.         Reference *new;
  100.  
  101.         new = (Reference *) ckalloc((unsigned)
  102.             (2*spaceAvl*sizeof(Reference)));
  103.         memcpy((VOID *) new, (VOID *) refArray, spaceAvl*sizeof(Reference));
  104.         ckfree((char *) refArray);
  105.         refArray = new;
  106.         spaceAvl *= 2;
  107.     }
  108.     }
  109.  
  110.     /*
  111.      * Make a new entry for the new reference.
  112.      */
  113.  
  114.     refPtr = &refArray[inUse];
  115.     refPtr->clientData = clientData;
  116.     refPtr->refCount = 1;
  117.     refPtr->mustFree = 0;
  118.     inUse += 1;
  119. }
  120.  
  121. /*
  122.  *----------------------------------------------------------------------
  123.  *
  124.  * Tk_Release --
  125.  *
  126.  *    This procedure is called to cancel a previous call to
  127.  *    Tk_Preserve, thereby allowing a block of memory to be
  128.  *    freed (if no one else cares about it).
  129.  *
  130.  * Results:
  131.  *    None.
  132.  *
  133.  * Side effects:
  134.  *    If Tk_EventuallyFree has been called for clientData, and if
  135.  *    no other call to Tk_Preserve is still in effect, the block of
  136.  *    memory is freed.
  137.  *
  138.  *----------------------------------------------------------------------
  139.  */
  140.  
  141. void
  142. Tk_Release(clientData)
  143.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  144. {
  145.     register Reference *refPtr;
  146.     int i;
  147.  
  148.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  149.     if (refPtr->clientData != clientData) {
  150.         continue;
  151.     }
  152.     refPtr->refCount--;
  153.     if (refPtr->refCount == 0) {
  154.         if (refPtr->mustFree) {
  155.         if (refPtr->freeProc == (Tk_FreeProc *) free) {
  156.             ckfree((char *) refPtr->clientData);
  157.         } else {
  158.             (*refPtr->freeProc)(refPtr->clientData);
  159.         }
  160.         }
  161.  
  162.         /*
  163.          * Copy down all of the trailing reference in the array
  164.          * to cover up the hole left by the unused reference.
  165.          */
  166.  
  167.         inUse--;
  168.         if (i != inUse) {
  169.         memcpy((VOID *) &refArray[i], (VOID *) &refArray[i+1],
  170.             (inUse-i)*sizeof(Reference));
  171.         }
  172.     }
  173.     return;
  174.     }
  175.  
  176.     /*
  177.      * Reference not found.  This is a bug in the caller.
  178.      */
  179.  
  180.     panic("Tk_Release couldn't find reference for 0x%x", clientData);
  181. }
  182.  
  183. /*
  184.  *----------------------------------------------------------------------
  185.  *
  186.  * Tk_EventuallyFree --
  187.  *
  188.  *    Free up a block of memory, unless a call to Tk_Preserve is in
  189.  *    effect for that block.  In this case, defer the free until all
  190.  *    calls to Tk_Preserve have been undone by matching calls to
  191.  *    Tk_Release.
  192.  *
  193.  * Results:
  194.  *    None.
  195.  *
  196.  * Side effects:
  197.  *    Ptr may be released by calling free().
  198.  *
  199.  *----------------------------------------------------------------------
  200.  */
  201.  
  202. void
  203. Tk_EventuallyFree(clientData, freeProc)
  204.     ClientData clientData;    /* Pointer to malloc'ed block of memory. */
  205.     Tk_FreeProc *freeProc;    /* Procedure to actually do free. */
  206. {
  207.     register Reference *refPtr;
  208.     int i;
  209.  
  210.     /*
  211.      * See if there is a reference for this pointer.  If so, set its
  212.      * "mustFree" flag (the flag had better not be set already!).
  213.      */
  214.  
  215.     for (i = 0, refPtr = refArray; i < inUse; i++, refPtr++) {
  216.     if (refPtr->clientData != clientData) {
  217.         continue;
  218.     }
  219.     if (refPtr->mustFree) {
  220.         panic("Tk_EventuallyFree called twice for 0x%x\n", clientData);
  221.         }
  222.         refPtr->mustFree = 1;
  223.     refPtr->freeProc = freeProc;
  224.         return;
  225.     }
  226.  
  227.     /*
  228.      * No reference for this block.  Free it now.
  229.      */
  230.  
  231.     if (freeProc == (Tk_FreeProc *) free) {
  232.     ckfree((char *) clientData);
  233.     } else {
  234.     (*freeProc)(clientData);
  235.     }
  236. }
  237.